// infer 是 TS 新增的关键字 充当占位符，一般使用在 extends 后

// 例：定义一个类型，如果传进来的值是数组类型就返回数组类型否则返回传进来的原类型
type TYPE<T> = T extends Array<infer arr> ? arr : T

type A = TYPE<(string | number)[]> // 这里传入的是数组可以看到类型推断 A 的类型就是对应类型的数组
type B = TYPE<boolean> // 这里传入的不是数组是布尔类型推断的值就是布尔

// 例：使用 infer 提取数组中的某项/某些元素
type Arr = ['a', 'b', 'c']
// 比如：提取数组的第一个元素
type First<T extends any[]> = T extends [infer first, ...any[]] ? first : []
type a = First<Arr> // type a = 'a'

// 比如：提取数组的最后一个元素
type Last<T extends any[]> = T extends [...any[], infer last] ? last : []
type b = Last<Arr> // type b = 'c'

// 比如：提取数组第一个元素和最后一个元素中间的元素(注意：这里返回的是一个数组，因为可能有多个元素)
type Center<T extends any[]> = T extends [unknown, ...infer center, unknown]
  ? center
  : []
type c = Center<Arr> // type c = ["b"]

// 比如：实现一个类似数组 pop方法（去掉数组最后一个元素
type pop<T extends any[]> = T extends [...infer arr, unknown] ? arr : []
type p = pop<Arr> // type p = ["a", "b"]

// 比如：实现一个类似数组 shift方法（去掉数组第一个元素
type shift<T extends any[]> = T extends [unknown, ...infer arr] ? arr : []
type s = shift<Arr> // type s = ["b", "c"]

// infer 递归的妙用
// 例：实现一个数组的翻转 [1, 2, 3, 4] -> [4, 3, 2, 1]
type list = [1, 2, 3, 4]
type ReverList<T extends any[]> = T extends [infer first, ...infer list]
  ? [...ReverList<list>, first]
  : T
type newList = ReverList<list> // type newList = [4, 3, 2, 1]
